package core;

import constant.Constant;
import util.FileUtils;
import util.HttpUtils;
import util.LogUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.concurrent.*;

public class Downloader {


    public ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);

    //创建线程池对象

    public ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor
            (Constant.THREAD_NUM, Constant.THREAD_NUM, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5));

    private CountDownLatch countDownLatch = new CountDownLatch(Constant.THREAD_NUM);
    public void downloader(String url) {
        //获取文件名
        String httpFileName = HttpUtils.getHttpFileName(url);

        //文件下载路径

        httpFileName = Constant.PATH + httpFileName;

        //获取本地文件大小

        long localFileLength = FileUtils.getFileContentLength(httpFileName);
        DownloaderInfoThread downloaderInfoThread = null;
        HttpURLConnection httpURLConnection = null;
        try {
            httpURLConnection = HttpUtils.getHttpURLConnection(url);
            //获取下载文件的大小
            int contentLength = httpURLConnection.getContentLength();

            if (localFileLength >= contentLength) {
                LogUtils.info("{} 已下载完成，无需重复下载", httpFileName);
                return;
            }

            //创建下载信息任务
            downloaderInfoThread = new DownloaderInfoThread(contentLength);

            scheduledExecutorService.scheduleAtFixedRate(downloaderInfoThread, 1, 1, TimeUnit.SECONDS);

            //切分任务
            ArrayList<Future> list = new ArrayList<>();

            split(url, list);

            countDownLatch.await();
//            //阻塞等待分块下载完成
//            list.forEach(future -> {
//                try {
//                    future.get();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                } catch (ExecutionException e) {
//                    e.printStackTrace();
//                }
//            });
            System.out.print("\r");
            //合并文件
            if(merge(httpFileName)){
                clearTemp(httpFileName);
            }


        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.print("\r");
            System.out.print("下载完成");

            if (httpURLConnection != null) {

                httpURLConnection.disconnect();

            }

            scheduledExecutorService.shutdownNow();

            //关闭线程池
            poolExecutor.shutdown();
        }
//
//        try {
//            //获取当前链接的输入流
//            InputStream inputStream = httpURLConnection.getInputStream();
//            //将输入流写入缓冲流
//            BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
//            //创建文件输出流
//            FileOutputStream fileOutputStream = new FileOutputStream(httpFileName);
//            //将缓冲流
//            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
//
//            int len = -1;
//            byte[] buffer = new byte[Constant.BYTE_SIZE];
//
//            while ((len = bufferedInputStream.read(buffer)) != -1) {
//                downloaderInfoThread.downSize.doubleValue() += len;
//                bufferedOutputStream.write(buffer, 0, len);
//            }
//        } catch (FileNotFoundException e) {
//            LogUtils.error("下载的文件 {} 不存在", url);
//
//        } catch (Exception e) {
//            LogUtils.error("下载失败");
//        } finally {
//            System.out.print("\r");
//            System.out.print("下载完成");
//
//            if (httpURLConnection != null) {
//
//                httpURLConnection.disconnect();
//
//            }
//
//            scheduledExecutorService.shutdownNow();
//        }
    }

    /**
     * 文件切分
     *
     * @param url
     * @param futureArrayList
     */
    public void split(String url, ArrayList<Future> futureArrayList) {
        try {
            //获取下载大小
            long contentLength = HttpUtils.getHttpFileContentLength(url);

            //计算切分后的大小
            long size = contentLength / Constant.THREAD_NUM;

            //计算开始分块大小
            for (int i = 0; i < Constant.THREAD_NUM; i++) {
                //起始位置
                long startPos = i * size;

                //计算结束位置
                long endPos;
                if (i == Constant.THREAD_NUM - 1) {
                    endPos = 0;
                } else {
                    endPos = startPos + size;
                }

                //如果不是第一块
                if (startPos != 0) {
                    startPos++;
                }

                //创建任务对象
                DownloaderTask downloaderTask = new DownloaderTask(url, startPos, endPos, i,countDownLatch);

                //将任务提交到线程池
                Future<Boolean> submit = poolExecutor.submit(downloaderTask);

                futureArrayList.add(submit);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 合并临时文件
     * @param fileName
     * @return
     */
    public boolean merge(String fileName) {
        LogUtils.info("开始合并文件 {}", fileName);

        byte[] buffer = new byte[Constant.BYTE_SIZE];

        int len = -1;

        try (RandomAccessFile randomAccessFile = new RandomAccessFile(fileName, "rw")) {
            for (int i = 0; i < Constant.THREAD_NUM; i++) {
                try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(fileName + ".temp" + i))) {

                    while ((len = bufferedInputStream.read(buffer)) != -1) {
                        randomAccessFile.write(buffer, 0, len);
                    }
                }
            }
            LogUtils.info("文件合并完成 {}", fileName);

        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

        System.out.println();
        return true;

    }

    /**
     * 清理临时文件
     * @param fileName
     * @return
     */
    public boolean clearTemp(String fileName){
        for (int i = 0; i < Constant.THREAD_NUM; i++) {
            File file = new File(fileName + ".temp" + i);
            file.delete();
        }

        return true;
    }


}
